package com.zhan.easyexcelorder.service.impl;


import com.zhan.easyexcelorder.model.SysDepartment;
import com.zhan.easyexcelorder.repository.SysDepartmentRepository;
import com.zhan.easyexcelorder.service.SysDepartmentService;
import com.zhan.jpa.service.impl.AbstractServiceImpl;
import com.zhan.utils.Constants;
import com.zhan.utils.page.PageResult;
import com.zhan.utils.page.QueryCondition;
import com.zhan.utils.page.QueryItem;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.*;

@Service
public class SysDepartmentServiceImpl extends AbstractServiceImpl<SysDepartmentRepository, SysDepartment> implements SysDepartmentService {

    @Transactional
    @Override
    public PageResult<SysDepartment> list(QueryCondition condition) {
        PageResult<SysDepartment> list = super.list(condition);
        addChildren(list.getData());
        return list;
    }

    private void addChildren(List<SysDepartment> list) {
        if (Objects.isNull(list) || list.isEmpty()) {
            return;
        }
        list.forEach(sysDepartment -> {
            sysDepartment.getChildren().size();
            addChildren(sysDepartment.getChildren());
        });
    }

    @Override
    protected void createPredicate(Root<SysDepartment> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder, List<Predicate> list, QueryCondition condition) {
        list.add(criteriaBuilder.equal(root.get("isDelete").as(Integer.class), Constants.NOT_DEL_VALUE));

        // 如果没有查询条件，则返回带子节点的，如果有查询条件，则返回所有的
        if (Objects.isNull(condition) || Objects.isNull(condition.getQuery()) || condition.getQuery().isEmpty()) {
            list.add(criteriaBuilder.isNull(root.get("parent").as(SysDepartment.class)));
        } else {
            List<QueryItem> query = condition.getQuery();
            query.forEach(queryItem -> {
                String column = queryItem.getColumn();
                if ("all".equals(column)) {
                    return;
                }
                if (StringUtils.isNotBlank(column) && StringUtils.isNotBlank(queryItem.getValue().toString())) {
                    list.add(criteriaBuilder.like(root.get("deptName").as(String.class), "%" + queryItem.getValue() + "%"));
                }
            });
        }
    }

    @Override
    protected void addEntity(SysDepartment entity) {
        SysDepartment parent = entity.getParent();
        if (Objects.nonNull(parent) && Objects.nonNull(parent.getId()) && !parent.getId().equals(0L)) {
            SysDepartment sysDepartment = repository.findById(parent.getId()).get();
            entity.setFullDepartmentName(sysDepartment.getFullDepartmentName() + "/" + entity.getDeptName());
            entity.setDeptLevel(sysDepartment.getDeptLevel() + 1);
        } else {
            entity.setDeptLevel(0);
            entity.setFullDepartmentName(entity.getDeptName());
        }
    }

    @Override
    protected void updateEntity(SysDepartment oldEntity, SysDepartment entity) {
        // 如果新的名称和旧的名称不一样
        if (StringUtils.isNotBlank(entity.getDeptName()) && !entity.getDeptName().equals(oldEntity.getDeptName())) {
            Integer level = oldEntity.getDeptLevel();
            String deptName = entity.getDeptName();
            List<SysDepartment> childrenList = new ArrayList<>();
            updateFullDepartmentName(oldEntity, deptName, level);
            entity.setChildren(childrenList);
        }
    }

    @Override
    protected void beforeDelete(SysDepartment entity) throws Exception {
        List<SysDepartment> children = entity.getChildren();
        if (!Objects.isNull(children) && !children.isEmpty()) {
            throw new Exception("有子部门，无法删除");
        }
    }

    private void updateFullDepartmentName(SysDepartment sysDepartment, String deptName, Integer level) {
        String fullDepartmentName = sysDepartment.getFullDepartmentName();
        String[] split = fullDepartmentName.split("/");
        StringBuffer stringBuffer = new StringBuffer();
        String result = "";
        for (int i = 0; i < split.length; i++) {
            if (i == level) {
                stringBuffer.append(deptName).append("/");
            } else {
                stringBuffer.append(split[i]).append("/");
            }
        }
        if (stringBuffer.toString().endsWith("/")) {
            result = stringBuffer.substring(0, stringBuffer.length() - 1);
        } else {
            result = stringBuffer.toString();
        }
        sysDepartment.setFullDepartmentName(result);
        if (Objects.nonNull(sysDepartment.getChildren()) && !sysDepartment.getChildren().isEmpty()) {
            sysDepartment.getChildren().forEach(temp -> {
                updateFullDepartmentName(temp, deptName, level);
            });
        }
    }

    @Transactional
    @Override
    public PageResult findAll(QueryCondition condition) {
        PageResult result = new PageResult();

        StringBuffer hql = new StringBuffer();
        hql.append("from SysDepartment d where d.isDelete=:isDelete");
        Map<String, Object> params = new HashMap<>();
        params.put("isDelete", Constants.NOT_DEL_VALUE);

        if (Objects.nonNull(condition)) {
            List<QueryItem> queryItems = condition.getQuery();
            if (Objects.nonNull(queryItems) && !queryItems.isEmpty()) {
                queryItems.forEach(queryItem -> {
                    String column = queryItem.getColumn();
                    if (StringUtils.isNotBlank(column) && StringUtils.isNotBlank(queryItem.getValue().toString())) {
                        hql.append(" and d.deptName like :deptName");
                        params.put("deptName", "%" + queryItem.getValue().toString() + "%");
                    }
                });
            }
        }


        Query query = this.entityManager.createQuery(hql.toString());
        params.forEach((key, value) -> query.setParameter(key, value));

        result.setData(query.getResultList());

        return result;
    }
}
